package com.adcc.ags.cgw.configuration;

import com.adcc.ags.cgw.App;
import com.adcc.ags.cgw.entity.user.*;
import com.adcc.ags.cgw.utils.Constant;
import com.adcc.ags.cgw.utils.FileUtil;
import com.adcc.utility.log.Log;
import com.adcc.utility.xml.*;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;

import java.io.File;
import java.util.List;

/**
 * 用户列表配置工厂类
 */
public class UserListFactory {

    // 单例
    private static UserListFactory instance;

    // 用户配置列表
    private List<User> userList = Lists.newArrayListWithExpectedSize(1000);

    /**
     * 构造函数
     */
    private UserListFactory(){

    }

    /**
     * 单例方法
     * @return
     */
    public synchronized static UserListFactory getInstance(){
        if(instance == null){
            instance = new UserListFactory();
        }
        return instance;
    }

    public List<User> getUserList() {
        return userList;
    }

    /**
     * 创建用户列表XML
     * @return
     */
    private ADCCXML formatUserList(){
        try{
            ADCCXML adccxml  = ADCCXMLFactory.getInstance().createADCCXML();
            adccxml.getRoot().put("version","1");
            adccxml.getRoot().put("type","GWUserList");
            SuperNode superNode = new SuperNode("userList");
            if(userList != null && userList.size() > 0){
                for(User user : userList){
                    Node node = new Node();
                    node.getAttributes().put("id",user.getId());
                    node.getAttributes().put("name",user.getName());
                    if(user.isDownlinkForward()){
                        node.getAttributes().put("downlinkForward","true");
                    }else {
                        node.getAttributes().put("downlinkForward","false");
                    }

                    Unit uSendQueue = new Unit();
                    uSendQueue.getAttributes().put("name","SendQueue");
                    uSendQueue.setText(user.getSendQueue());
                    node.getUnitList().add(uSendQueue);

                    Unit uRecvQueue = new Unit();
                    uRecvQueue.getAttributes().put("name","RecvQueue");
                    uRecvQueue.setText(user.getRecvQueue());
                    node.getUnitList().add(uRecvQueue);

                    Unit uType = new Unit();
                    uType.getAttributes().put("name", "MsgType");
                    if(user.getMsgType() == MsgType.SplitResult){
                        uType.setText("SplitResult");
                    }else{
                        uType.setText("RawMsg");
                    }
                    node.getUnitList().add(uType);

                    if(user.getRouteList() != null && user.getRouteList().size() > 0){
                        for(Route route : user.getRouteList()){
                            Node childNode = new Node(ADCCXML.CHILD_NODE_NAME);
                            childNode.getAttributes().put("id",route.getId());
                            childNode.getAttributes().put("name",route.getName());
                            if(route.getType() == RouteType.Uplink){
                                childNode.getAttributes().put("type","Uplink");

                                if(!Strings.isNullOrEmpty(((UplinkRoute) route).getSendAddress())){
                                    Unit uSendAddress = new Unit();
                                    uSendAddress.getAttributes().put("name","SendAddress");
                                    uSendAddress.setText(((UplinkRoute)route).getSendAddress());
                                    childNode.getUnitList().add(uSendAddress);
                                }

                                if(((UplinkRoute)route).getRecvAddress() != null && ((UplinkRoute)route).getRecvAddress().length > 0){
                                    Unit uRecvAddress = new Unit();
                                    uRecvAddress.getAttributes().put("name","RecvAddress");
                                    uRecvAddress.setText(this.arrayToString(((UplinkRoute) route).getRecvAddress()));
                                    childNode.getUnitList().add(uRecvAddress);
                                }

                                if(((UplinkRoute)route).getSmi() != null && ((UplinkRoute)route).getSmi().length > 0){
                                    Unit uSMI = new Unit();
                                    uSMI.getAttributes().put("name","SMI");
                                    uSMI.setText(this.arrayToString(((UplinkRoute)route).getSmi()));
                                    childNode.getUnitList().add(uSMI);
                                }

                                if(((UplinkRoute)route).getAn() != null && ((UplinkRoute)route).getAn().length > 0){
                                    Unit uAN = new Unit();
                                    uAN.getAttributes().put("name","AN");
                                    uAN.setText(this.arrayToString(((UplinkRoute)route).getAn()));
                                    childNode.getUnitList().add(uAN);
                                }

                                if(((UplinkRoute)route).getSpecLabel() != null && ((UplinkRoute)route).getSpecLabel().getIndex() > 0){
                                    Unit uSpecLabel = new Unit();
                                    uSpecLabel.getAttributes().put("name","SpecLabel");
                                    uSpecLabel.getAttributes().put("index", String.valueOf(((UplinkRoute) route).getSpecLabel().getIndex()));
                                    uSpecLabel.setText(((UplinkRoute)route).getSpecLabel().getContent());
                                    childNode.getUnitList().add(uSpecLabel);
                                }

                                if(((UplinkRoute)route).getDestination() != null && ((UplinkRoute)route).getDestination().length > 0){
                                    Unit uDestination = new Unit();
                                    uDestination.getAttributes().put("name","Destination");
                                    uDestination.setText(this.arrayToString(((UplinkRoute)route).getDestination()));
                                    childNode.getUnitList().add(uDestination);
                                }

                            }else if(route.getType() == RouteType.Ground){
                                childNode.getAttributes().put("type","Ground");

                                if(((GroundRoute)route).getSpecLabel() != null && ((UplinkRoute)route).getSpecLabel().getIndex() > 0){
                                    Unit uSpecLabel = new Unit();
                                    uSpecLabel.getAttributes().put("name","SpecLabel");
                                    uSpecLabel.getAttributes().put("index",String.valueOf(((GroundRoute) route).getSpecLabel().getIndex()));
                                    uSpecLabel.setText(((GroundRoute)route).getSpecLabel().getContent());
                                    childNode.getUnitList().add(uSpecLabel);
                                }

                                if(((GroundRoute)route).getDestination() != null && ((GroundRoute)route).getDestination().length > 0){
                                    Unit uDestination = new Unit();
                                    uDestination.getAttributes().put("name","Destination");
                                    uDestination.setText(this.arrayToString(((GroundRoute) route).getDestination()));
                                    childNode.getUnitList().add(uDestination);
                                }
                            }else{
                                childNode.getAttributes().put("type","Downlink");

                                if(!Strings.isNullOrEmpty(((DownlinkRoute) route).getSendAddress())){
                                    Unit uSendAddress = new Unit();
                                    uSendAddress.getAttributes().put("name","SendAddress");
                                    uSendAddress.setText(((DownlinkRoute) route).getSendAddress());
                                    childNode.getUnitList().add(uSendAddress);
                                }

                                if(((DownlinkRoute)route).getRecvAddress() != null && ((DownlinkRoute)route).getRecvAddress().length > 0){
                                    Unit uRecvAddress = new Unit();
                                    uRecvAddress.getAttributes().put("name","RecvAddress");
                                    uRecvAddress.setText(this.arrayToString(((DownlinkRoute)route).getRecvAddress()));
                                    childNode.getUnitList().add(uRecvAddress);
                                }

                                if(((DownlinkRoute)route).getSmi() != null && ((DownlinkRoute)route).getSmi().length > 0){
                                    Unit uSMI = new Unit();
                                    uSMI.getAttributes().put("name","SMI");
                                    uSMI.setText(this.arrayToString(((DownlinkRoute)route).getSmi()));
                                    childNode.getUnitList().add(uSMI);
                                }

                                if(((DownlinkRoute)route).getAn() != null && ((DownlinkRoute)route).getAn().length > 0){
                                    Unit uAN = new Unit();
                                    uAN.getAttributes().put("name","AN");
                                    uAN.setText(this.arrayToString(((DownlinkRoute) route).getAn()));
                                    childNode.getUnitList().add(uAN);
                                }

                                if(((DownlinkRoute)route).getFi() != null && ((DownlinkRoute)route).getFi().length > 0){
                                    Unit uFI = new Unit();
                                    uFI.getAttributes().put("name","FI");
                                    uFI.setText(this.arrayToString(((DownlinkRoute) route).getFi()));
                                    childNode.getUnitList().add(uFI);
                                }

                                if(((DownlinkRoute)route).getRgs() != null && ((DownlinkRoute)route).getRgs().length > 0){
                                    Unit uRGS = new Unit();
                                    uRGS.getAttributes().put("name","RGS");
                                    uRGS.setText(this.arrayToString(((DownlinkRoute)route).getRgs()));
                                    childNode.getUnitList().add(uRGS);
                                }

                                if(((DownlinkRoute)route).getSpecLabel() != null && ((DownlinkRoute)route).getSpecLabel().getIndex() > 0){
                                    Unit uSpecLabel = new Unit();
                                    uSpecLabel.getAttributes().put("name","uSpecLabel");
                                    uSpecLabel.getAttributes().put("index",String.valueOf(((DownlinkRoute) route).getSpecLabel().getIndex()));
                                    uSpecLabel.setText(((DownlinkRoute) route).getSpecLabel().getContent());
                                    childNode.getUnitList().add(uSpecLabel);
                                }
                            }
                            node.getSubNodeList().add(childNode);
                        }
                    }
                    superNode.getNodeList().add(node);
                }
            }
            adccxml.getSuperNodeList().add(superNode);
            return adccxml;
        }catch (Exception ex){
            Log.error(UserListFactory.class.getName(),"formatUserList() error",ex);
            return null;
        }
    }

    /**
     * 解析用户列表，如果backup为false，则解析出用户全部为主用User，否则全部为备用User
     * @param adccxml
     * @throws Exception
     */
    private List<User> parseUserList(ADCCXML adccxml, boolean backup)throws Exception{
        try {
            List<User> userList = Lists.newArrayList();
            SuperNode userNode = adccxml.getSuperNode("userList");
            if(userNode == null){
                throw new NullPointerException("parse xml error reason:lose <userList></userList>");
            }
            for(Node node : userNode.getNodeList()){
                if(node.getAttributes().containsKey("id") && node.getAttributes().containsKey("name") && node.getAttributes().containsKey("downlinkForward")){
                    String strID = node.getAttributes().get("id").trim();
                    String strName = node.getAttributes().get("name").trim();
                    User user = new User(strID,strName);
                    user.setBackup(backup);
                    if("true".equals(node.getAttributes().get("downlinkForward").trim())){
                        user.setDownlinkForward(true);
                    }else{
                        user.setDownlinkForward(false);
                    }
                    if(node.getUnitList().size() > 0){
                        for(Unit unit : node.getUnitList()){
                            if("SendQueue".equals(unit.getAttributes().get("name"))){
                                user.setSendQueue(unit.getText());
                            }
                            if("RecvQueue".equals(unit.getAttributes().get("name"))){
                                user.setRecvQueue(unit.getText());
                            }
                            if("MsgType".equals(unit.getAttributes().get("name"))){
                                if(MsgType.SplitResult.toString().equals(unit.getText())){
                                    user.setMsgType(MsgType.SplitResult);
                                }else{
                                    user.setMsgType(MsgType.RawMsg);
                                }
                            }
                        }
                    }
                    if(node.getSubNodeList().size() > 0){
                        for(Node routeNode : node.getSubNodeList()){
                            if(routeNode.getAttributes().containsKey("id") && routeNode.getAttributes().containsKey("name") && routeNode.getAttributes().containsKey("type")){
                                String strRouteID = routeNode.getAttributes().get("id").trim();
                                String strRouteName = routeNode.getAttributes().get("name").trim();
                                if("Downlink".equals(routeNode.getAttributes().get("type").trim())){
                                    Route route = new DownlinkRoute(strRouteID,strRouteName,RouteType.Downlink);
                                    if(routeNode.getUnitList().size() > 0){
                                        for(Unit unit : routeNode.getUnitList()){
                                            if("SendAddress".equals(unit.getAttributes().get("name").trim())){
                                                ((DownlinkRoute)route).setSendAddress(unit.getText().trim());
                                            }
                                            if("RecvAddress".equals(unit.getAttributes().get("name").trim())){
                                                String srtRecvAddress = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(srtRecvAddress)){
                                                    ((DownlinkRoute)route).setRecvAddress(srtRecvAddress.split(","));
                                                }
                                            }
                                            if("SMI".equals(unit.getAttributes().get("name").trim())){
                                                String strSMI = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strSMI)){
                                                    ((DownlinkRoute)route).setSmi(strSMI.split(","));
                                                }
                                            }
                                            if("FI".equals(unit.getAttributes().get("name").trim())){
                                                String strFI = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strFI)){
                                                    ((DownlinkRoute)route).setFi(strFI.split(","));
                                                }
                                            }
                                            if("AN".equals(unit.getAttributes().get("name").trim())){
                                                String strAN = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strAN)){
                                                    ((DownlinkRoute)route).setAn(strAN.split(","));
                                                }
                                            }
                                            if("RGS".equals(unit.getAttributes().get("name").trim())){
                                                String strRGS = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strRGS)){
                                                    ((DownlinkRoute)route).setRgs(strRGS.split(","));
                                                }
                                            }
                                            if("SpecLabel".equals(unit.getAttributes().get("name").trim())){
                                                SpecLabel specLabel = new SpecLabel();
                                                specLabel.setContent(unit.getText().trim());
                                                try {
                                                    String strIndex = unit.getAttributes().get("index").trim();
                                                    if(!Strings.isNullOrEmpty(strIndex)) {
                                                        specLabel.setIndex(Integer.parseInt(strIndex));
                                                    }
                                                } catch (Exception e) {
                                                    Log.error(UserListFactory.class.getName(), "parse xml error reason: invalid speclabel index");
                                                }
                                                ((DownlinkRoute)route).setSpecLabel(specLabel);
                                            }
                                        }
                                    }
                                    user.getRouteList().add(route);
                                }
                                if("Uplink".equals(routeNode.getAttributes().get("type").trim())){
                                    Route route = new UplinkRoute(strRouteID,strRouteName,RouteType.Uplink);
                                    if(routeNode.getUnitList().size() > 0){
                                        for(Unit unit : routeNode.getUnitList()){
                                            if("SendAddress".equals(unit.getAttributes().get("name").trim())){
                                                ((UplinkRoute)route).setSendAddress(unit.getText().trim());
                                            }
                                            if("RecvAddress".equals(unit.getAttributes().get("name").trim())){
                                                String srtRecvAddress = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(srtRecvAddress)){
                                                    ((UplinkRoute)route).setRecvAddress(srtRecvAddress.split(","));
                                                }
                                            }
                                            if("Destination".equals(unit.getAttributes().get("name").trim())){
                                                String srtDestination = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(srtDestination)){
                                                    ((UplinkRoute)route).setDestination(srtDestination.split(","));
                                                }
                                            }
                                            if("SMI".equals(unit.getAttributes().get("name").trim())){
                                                String strSMI = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strSMI)){
                                                    ((UplinkRoute)route).setSmi(strSMI.split(","));
                                                }
                                            }
                                            if("AN".equals(unit.getAttributes().get("name").trim())){
                                                String strAN = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(strAN)){
                                                    ((UplinkRoute)route).setAn(strAN.split(","));
                                                }
                                            }
                                            if("SpecLabel".equals(unit.getAttributes().get("name").trim())){
                                                SpecLabel specLabel = new SpecLabel();
                                                specLabel.setContent(unit.getText().trim());
                                                try {
                                                    String strIndex = unit.getAttributes().get("index").trim();
                                                    if(!Strings.isNullOrEmpty(strIndex)) {
                                                        specLabel.setIndex(Integer.parseInt(strIndex));
                                                    }
                                                } catch (Exception e) {
                                                    Log.error(UserListFactory.class.getName(), "parse xml error reason: invalid speclabel index");
                                                }
                                                ((UplinkRoute)route).setSpecLabel(specLabel);
                                            }
                                        }
                                    }
                                    user.getRouteList().add(route);
                                }
                                if("Ground".equals(routeNode.getAttributes().get("type").trim())){
                                    Route route = new GroundRoute(strRouteID,strRouteName,RouteType.Ground);
                                    if(routeNode.getUnitList().size() > 0){
                                        for(Unit unit : routeNode.getUnitList()) {
                                            if("Destination".equals(unit.getAttributes().get("name").trim())){
                                                String srtDestination = unit.getText().trim();
                                                if(!Strings.isNullOrEmpty(srtDestination)){
                                                    ((GroundRoute)route).setDestination(srtDestination.split(","));
                                                }
                                            }
                                            if("SpecLabel".equals(unit.getAttributes().get("name").trim())){
                                                SpecLabel specLabel = new SpecLabel();
                                                specLabel.setContent(unit.getText().trim());
                                                try {
                                                    String strIndex = unit.getAttributes().get("index").trim();
                                                    if(!Strings.isNullOrEmpty(strIndex)) {
                                                        specLabel.setIndex(Integer.parseInt(strIndex));
                                                    }
                                                } catch (Exception e) {
                                                    Log.error(UserListFactory.class.getName(), "parse xml error reason: invalid speclabel index");
                                                }
                                                ((GroundRoute)route).setSpecLabel(specLabel);
                                            }
                                        }
                                    }
                                    user.getRouteList().add(route);
                                }
                            }
                        }
                    }
                    userList.add(user);
                }
            }
            return userList;
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "parseUserList() error", ex);
            throw ex;
        }
    }

    /**
     * 加载用户列表
     * @return
     */
    public ADCCXML load() throws Exception{
        try {
            ADCCXML adccxml = null;
            String strUserListFile = App.confPath + File.separator + Constant.STRING_USERLIST_FILE;
            if (FileUtil.isExist(strUserListFile)) {
                adccxml = ADCCXMLFactory.getInstance().createADCCXML();
                adccxml.parseXMLFile(strUserListFile);
                userList = parseUserList(adccxml, false);
            }
            return adccxml;
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "load() error", ex);
            throw ex;
        }
    }

    /**
     * 保存用户列表
     */
    public void save() {
        try {
            String strUserListFile = App.confPath+ File.separator + Constant.STRING_USERLIST_FILE;
            ADCCXML adccxml = this.formatUserList();
            if(adccxml != null){
                adccxml.createXMLFile(strUserListFile, XMLPattern.PRETTY);
            }
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "save() error", ex);
        }
    }

    /**
     * 保存用户列表
     * @param xml
     */
    public void save(String xml) {
        try {
            String strUserListFile = App.confPath + File.separator + Constant.STRING_USERLIST_FILE;
            ADCCXML adccxml = ADCCXMLFactory.getInstance().createADCCXML();
            adccxml.parseXMLString(xml);
            adccxml.createXMLFile(strUserListFile, XMLPattern.PRETTY);
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "save() error", ex);
        }
    }

    /**
     * 新增网关用户
     * @param user
     */
    public void addUser(User user) {
        if(userList != null && userList.size() > 0){
            for(User u : userList){
                if(u.getId().equals(user.getId()) && u.getName().equals(user.getName())){
                    return;
                }
            }
        }
        userList.add(user);
    }

    /**
     * 删除网关用户
     * @param userId
     * @param userName
     */
    public void deleteUser(String userId,String userName){
        if(userList != null && userList.size() > 0){
            for(User u : userList){
                if(u.getId().equals(userId) && u.getName().equals(userName)){
                    userList.remove(u);
                    return;
                }
            }
        }
    }

    /**
     * 删除用户列表中的用户，如果backup为false，则删除全部的主用User，否则删除全部的备用User
     * @param backup
     * @exception java.lang.Exception zyy 2016-12-06 添加
     * */
    public void deleteAllUser(boolean backup) throws Exception{
        try {
            if (userList.size() > 0) {
                List<User> tempList = Lists.newArrayListWithExpectedSize(userList.size());
                for (User user : userList) {
                    if (user.isBackup() == backup) {
                        tempList.add(user);
                    }
                }
                userList.removeAll(tempList);
            }
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "deleteAllUser() error", ex);
            throw ex;
        }
    }

    /**
     * 更新用户列表中的用户，如果backup为false，则更新主用User，否则更新备用User
     * @param adccxml
     * @param backup
     * @exception java.lang.Exception zyy 2016-12-06 添加
     * */
    public void updateUserList(ADCCXML adccxml, boolean backup) throws Exception{
        try {
            // 删除已有的User
            deleteAllUser(backup);

            // 解析用户列表，添加新的User
            userList.addAll(parseUserList(adccxml, backup));
        } catch (Exception ex) {
            Log.error(UserListFactory.class.getName(), "updateUserList() error", ex);
            throw ex;
        }
    }

    /**
     * String[]转String，以英文逗号隔开
     * @param strArray
     * @return
     */
    private String arrayToString(String[] strArray){
        String str = Strings.nullToEmpty("");
        for(String st : strArray){
            str += st + ",";
        }
        if (str.endsWith(",")) {
            str = str.substring(0, str.length() - 1);
        }
        return str;
    }

}
